package client;

import java.rmi.AlreadyBoundException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;
import java.util.concurrent.ExecutionException;
import java.util.logging.Logger;

import remote.RemoteDistributedHashMap;
import remote.RemoteFuture;

public class TokenClient
{

  /**
   * Registry name
   */
  private static String REGISTRY_NAME = "RemoteRegistry";
  /**
   * rmi registry.
   */
  private static Registry registry;
  /**
   * Private constructor to prevent instantiation.
   */
  private TokenClient()
  {
    // do nothing
  }
  /**
   * 
   */
  public static String rmi_NodeFind(final int node_num) 
  {
    final String rmi_name_actual = new Integer(node_num).toString() + "A";
    final String rmi_name_virtual = new Integer(node_num).toString() + "V";
    try
    {
      if (registry.lookup(rmi_name_actual) == null)
      {
        return rmi_name_virtual;
      }
      else
      {
        return rmi_name_actual;
      }
    }
    catch (final RemoteException | NotBoundException e)
    {
      System.out.println(" an error occured " + e);
      System.exit(1);
    }
    return rmi_name_virtual;
  }


  /**
   * The main method to run token client. The first command line argument is the hostname of the
   * registry; the second is the port number of the registry; third is the
   * optional remote registry name.
   * 
   * @param the_args Used as described in the method description.
   * @throws ExecutionException
   * @throws InterruptedException
   * @throws AlreadyBoundException
   */
  public static void main(final String[] the_args) throws InterruptedException 
  {
    try
    {
      String registry_name = REGISTRY_NAME;
      if (the_args.length < 3)
      {
        System.out
            .println("Usage <rmi registry host> <rmi registry port> <remote rmiregistry name>");
        System.exit(1);
      }
      final String host = the_args[0];
      final int port = Integer.parseInt(the_args[1]);
      final Registry bootstrap = LocateRegistry.getRegistry(host, port);
      registry = (Registry) bootstrap.lookup(the_args[2]);
      final ArrayList<String> registry_list =  new 
          ArrayList<String>(Arrays.asList(registry.list()));
      System.out.println(" list of nodes in the registry are  " +
                         Arrays.toString(registry.list()));
      System.out.println(" Select a node - ");
      // open up standard input
      String node_name;
      String operation;
      String key;
      String value;
      final Scanner scanner = new Scanner(System.in);
      node_name = scanner.nextLine();
      if (node_name.trim().isEmpty())
      {
        System.out.println("Hmm, I didn't get node name");
        System.exit(1);
      }
      if (!(node_name.trim().endsWith("V") || node_name.trim().endsWith("A")))
      {
        node_name = rmi_NodeFind(new Integer(node_name).intValue());
      }
      if (!registry_list.contains(node_name))
      {
        System.out.println("the given node number is not found in the rmi registry");
        System.exit(1);
      }
      final RemoteDistributedHashMap map =
          (RemoteDistributedHashMap) registry.lookup(node_name);
      RemoteFuture result;      
      System.out.println("Select a token operation ) -(FIRSTKEY, LASTKEY, TOTALCOUNT, ACTUALCOUNT ");
      operation = scanner.nextLine();
      if (operation.trim().isEmpty())
      {
        System.out.println("Hmm, I didn't get operation name");
      }
      if ("FIRSTKEY".equalsIgnoreCase(operation))
      {
        result = (RemoteFuture) map.firstKey();
        System.out.println("First key value: " + result.blockingGet());
      }
      if ("LASTKEY".equalsIgnoreCase(operation))
      {
         result = (RemoteFuture) map.lastKey();
        System.out.println("Last key value:" + result.blockingGet());
      }
      if ("ACTUALCOUNT".equalsIgnoreCase(operation))
      {
        result = (RemoteFuture) map.actualCount();
        System.out.println("Actual node list: " + result.blockingGet());
      }
      if ("TOTALCOUNT".equalsIgnoreCase(operation))
      {
        result = (RemoteFuture) map.totalCount();
        System.out.println("Total Keys: " + result.blockingGet());
      }
    }
    catch (final RemoteException e)
    {
      System.err.println("A problem occurred: " + e);
      System.exit(1);
    }
    catch (final NotBoundException e)
    {
      System.err.println("Could not find RMI server.");
      System.exit(1);
    }
  }
}
